package com.artic.base.xml;


import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;


/**
 * 
 * @author czarnik_a
 * 
 */
public class XMLJaxbReader<T> {

	private static final String HTTP_W3_XMLSCHEMA = "http://www.w3.org/2001/XMLSchema";
	/**
	 * This Class introduces the reader to the basics of XML handle.
	 */
	private final Unmarshaller.Listener listener;

	/**
	 * <p>
	 * listener-only constructor, initializes a Listener the given validation.
	 * </p>
	 * 
	 * @param listener
	 */
	public XMLJaxbReader(Unmarshaller.Listener listener) {
		this.listener = listener;
	}

	/**
	 * <p>
	 * Default no-argument constructor.
	 * </p>
	 */
	public XMLJaxbReader() {
		this(new XMLUnmarshallerListener());
	}

	/**
	 * return complete vailded xml-class graph.
	 * 
	 * @param context
	 *            A colon separated path of package names where to look for
	 *            jaxb.properties files. The package names must match the
	 *            generated classes which you are going to use in your
	 *            application.
	 * @param schemafile
	 *            File that represents a schema.
	 * @param inputStream
	 *            The XML inputStream that represents a xml file.
	 * @return the newly created root object of the java content tree.
	 * 
	 * @throws XMLReadException
	 */
	@SuppressWarnings("unchecked")
	public JAXBElement<T> read(String context, URL schemafile,
			InputStreamReader inputStream) {

		try {
			JAXBContext jc = JAXBContext.newInstance(context, this.getClass()
					.getClassLoader());
			Unmarshaller unmarshaller = jc.createUnmarshaller();
			unmarshaller.setEventHandler(new XMLValidationHandler());
			unmarshaller.setListener(listener);
			SchemaFactory sf = SchemaFactory.newInstance(HTTP_W3_XMLSCHEMA);
			Schema schema = sf.newSchema(schemafile);
			unmarshaller.setSchema(schema);

			JAXBElement<T> properties = (JAXBElement<T>) unmarshaller.unmarshal(inputStream);
			return properties;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

    /**
     * Returns the JAXBElement buildup from the given parameters.
     * <p>
     * This method returns the configuration object.
     * </p>
     * 
     * @param context
     *        the package name as context.
     * @param schema
     *        the xsd-file to the schema.
     * @param xmlstream
     *        the stream to the xmlfile.
     * @param encoding
     *        the default encoding type.
     * @return the buildup configuration object graph.
     */
    @SuppressWarnings("unchecked")
    public JAXBElement readElement(String context, URL schema,
            InputStream xmlstream, String encoding) {
        InputStreamReader fileReader;
        try {
            fileReader = new InputStreamReader(xmlstream, encoding);
            if (fileReader.ready()) {
            	JAXBElement jaxbelement = this.read(context, schema, fileReader);
                return jaxbelement;
            }
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
}
